import { Utils } from "../../framework/utils/Utils";

/**
 * 游戏逻辑管理，数据类
 * @author 黄学捷，黄大师
 */
export class GameLogicMgr {
    private constructor() { }
    static _instance: GameLogicMgr;
    static get instance(): GameLogicMgr {
        if (!GameLogicMgr._instance) {
            GameLogicMgr._instance = new GameLogicMgr();
        }
        return GameLogicMgr._instance;
    }
    private _skillUseStatus: boolean = false;


    /**新玩法的色块规则,遮罩快 */
    private _curMaskColorBlock: { id: string, x: number, y: number }[] = [];
    /** 
     * 获取当前遮罩块数据
     * @returns
     */
    get curMaskColorBlock(): { id: string, x: number, y: number }[] {
        return this._curMaskColorBlock;
    }
    /**
     * 设置当前遮罩块数据
     * @param value
     */
    protected set curMaskColorBlock(value: { id: string, x: number, y: number }[]) {
        this._curMaskColorBlock = value;
    }
    /**技能使用状态 */
    get skillUseStatus(): boolean {
        return this._skillUseStatus;
    }
    /**
     * 设置技能使用状态
     * @param value
     */
    set skillUseStatus(value: boolean) {
        this._skillUseStatus = value;
    }

    /**等级数据 */
    private _levelData: levelData[][];
    /**
     * 设置等级数据
     * @param value
     */
    protected set levelData(value: levelData[][]) {
        // const beforeData = Utils.clonObj(this.levelData);
        this._levelData = value;
        // console.log("设置之前的数据", beforeData);
        console.log("设置之后的数据", this.levelData);
    }
    /**
     * 获取等级数据
     * @returns
     */
    get levelData(): levelData[][] {
        return this._levelData;
    }
    get levelDataByNumberArr(): number[][] {
        let arr: number[][] = [];
        for (let i = 0; i < this.levelData.length; i++) {
            arr[i] = [];
            for (let j = 0; j < this.levelData[i].length; j++) {
                arr[i][j] = this.levelData[i][j].value;
            }
        }
        return arr;
    }
    init() {
        this.levelData = [];
        this._skillUseStatus = false;
        this.curMaskColorBlock = [];

    };
    /**游戏是否暂停 */
    public isPause = false;
    /**暂停游戏 */
    public pauseGame() {
        console.log("暂停游戏");
        // 暂停游戏逻辑
        this.isPause = true;
    }
    /**恢复游戏 */
    public resumeGame() {
        console.log("恢复游戏");
        // 恢复游戏逻辑
        this.isPause = false;
    }
    /**
 * 在十字方向上查找第一个非零色块
 * @param row 点击的行
 * @param col 点击的列
 * @returns 包含非零色块信息的数组
 */
    public findNonZeroBlocksInCross(row: number, col: number): { row: number; col: number; value: number, maskCount: number, maskType: number }[] {
        // 检查输入的行和列是否越界
        if (row < 0 || row >= this.levelData.length || col < 0 || col >= this.levelData[0].length) {
            return [];
        }

        const objArr: { row: number; col: number; value: number, maskCount: number, maskType: number }[] = [];
        const directions: [number, number][] = [[0, 1], [0, -1], [1, 0], [-1, 0]];

        for (const [dr, dc] of directions) {
            let r = row + dr;
            let c = col + dc;

            while (r >= 0 && r < this.levelData.length && c >= 0 && c < this.levelData[r].length) {
                if (this.levelData[r][c].value > 0) {
                    objArr.push({ row: r, col: c, value: this.levelData[r][c].value, maskCount: this.levelData[r][c].maskCount, maskType: this.levelData[r][c].maskType });
                    break;
                }
                r += dr;
                c += dc;
            }
        }

        return objArr;
    }


    /**
    * 查找满足十字消除条件的零值位置及其对应的非零色块信息
    * @returns 包含满足条件的零值位置及其对应非零色块信息的数组
    */
    public findZeroBlocks() {
        // 用于存储满足条件的零值位置及其对应的非零色块信息
        //     y       x      maskCount
        const zeroBlocks: { blocks: [number, number, number, number][], value: number, clickPos: number[] }[] = [];
        // 遍历二维数组的每一行
        for (let row = 0; row < this.levelData.length; row++) {
            // 遍历当前行的每一列
            for (let col = 0; col < this.levelData[row].length; col++) {
                // 检查当前位置的值是否为 0
                if (this.levelData[row][col].value === 0) {
                    // 查找当前位置十字方向上的第一个非零色块
                    const objArr = this.findNonZeroBlocksInCross(row, col);
                    // 对找到的非零色块按值进行分组
                    const obj = this.groupBlocksByValue(objArr);
                    const isMaskType2Arr:number[][] = []
                    // 遍历分组后的对象
                    for (const key in obj) {
                        for (let i = obj[key].length - 1; i >= 0; i--) {
                            if (obj[key][i][3] === 2) {
                                isMaskType2Arr.push(obj[key].splice(i, 1)[0]);
                            }
                        }
                        if (obj[key].length === 0) {
                            delete obj[key];
                        }
                    }
                    obj['mask'] = isMaskType2Arr;
                    for (const key in obj) {
                        // 如果某个值对应的色块数量大于等于 2
                        if (obj[key].length >= 2) {
                            // 将该值和对应的色块位置数组添加到 zeroBlocks 数组中
                            zeroBlocks.push({ value: Number(key), blocks: obj[key], clickPos: [row, col] });
                        }
                    }
                }
            }
        }
        // 返回满足条件的零值位置及其对应非零色块信息的数组
        return zeroBlocks;
    }


    /**
     * 按值对找到的色块进行分组
     * @param objArr 包含非零色块信息的数组
     * @returns 分组后的对象
     */
    public groupBlocksByValue(objArr: { row: number; col: number; value: number, maskCount: number, maskType: number }[]): { [key: number]: [number, number, number, number][] } {
        //     y       x      maskCount
        const obj: { [key: number]: [number, number, number, number][] } = {};

        for (const item of objArr) {
            if (!obj[item.value]) {
                obj[item.value] = [];
            }
            obj[item.value].push([item.row, item.col, item.maskCount, item.maskType]);
        }

        return obj;
    }
    //随机生成消除色块矩阵   
    /**
     * @deprecated 已经弃用，请使用generateColorGrid1方法+
    * 生成一个二维数组，接收四个参数，row,col,数量，颜色代号1~7数组表示[1,2,3,4,5,6,7],每个色块是2的倍数
    * @param row 行数
    * @param col 列数
    * @param count 数量
    * @returns 生成的二维数组
    */
    public generateColorGrid(row: number, col: number, count: number, colorBlocks: number[] = [1, 2, 3, 4, 5, 6, 7]) {
        // 创建一个空的二维数组
        const grid = Array.from({ length: row }, () => Array(col).fill(0));

        // 检查总数量是否超过数组的大小
        const totalBlocks = row * col;
        if (count > totalBlocks) {
            throw new Error("总数量不能超过数组的大小");
        }

        // 生成颜色块
        const colors = [];
        for (let i = 0; i < count; i++) {
            // 随机选择颜色代号
            const color = colorBlocks[Math.floor(Math.random() * colorBlocks.length)];
            colors.push(color);
        }

        // 统计每种颜色的数量
        const colorCount = {};
        colors.forEach(color => {
            colorCount[color] = (colorCount[color] || 0) + 1;
        });

        // 确保每种颜色的数量是2的倍数
        for (const color in colorCount) {
            while (colorCount[color] % 2 !== 0) {
                // 添加一个额外的颜色以确保是2的倍数
                colors.push(Number(color));
                colorCount[color]++;
            }
        }
        // 填充二维数组
        let placedCount = 0;
        while (placedCount < colors.length) {
            const randomRow = Math.floor(Math.random() * row);
            const randomCol = Math.floor(Math.random() * col);
            if (grid[randomRow][randomCol] === 0) { // 确保该位置未被占用
                grid[randomRow][randomCol] = colors[placedCount]; // 填充色块
                placedCount++;
            }
        }
        this.levelData = grid;
    }
    /**
     * 生成一个二维数组，接收四个参数，row,col,数量，颜色代号1~7数组表示[1,2,3,4,5,6,7],每个色块是2的倍数
     * @param row 行数
     * @param col 列数
     * @param count 数量
     * @param siamese 同色块数量
     * @param colorBlocks 颜色代号数组
     */
    public generateColorGrid1(row: number, col: number, count: number, siamese, colorBlocks: number[], siameseRandom: number) {
        // 创建一个空的二维数组
        let grid = Array.from({ length: row }, (_, y) => Array(col).fill(0).map((_, x) => (
            { value: 0, maskCount: 0, maskType: -1, y: y, x: x }
        ))) as levelData[][];

        // 检查总数量是否超过数组的大小
        const totalBlocks = row * col;
        if (count > totalBlocks) {
            count = totalBlocks;
            // throw new Error("总数量不能超过数组的大小");
        }

        // 生成颜色块
        const colors = [];
        for (let i = 0; i < count; i++) {
            const color = colorBlocks[Math.floor(Math.random() * colorBlocks.length)];
            colors.push(color);
        }

        // 统计每种颜色的数量
        const colorCount = {};
        colors.forEach(color => {
            colorCount[color] = (colorCount[color] || 0) + 1;
        });
        // 尝试放置颜色块
        for (const color in colorCount) {
            let placed = 0;
            const maxCount = colorCount[color];

            while (placed < maxCount) {
                // 随机选择一个起始位置
                const startRow = Math.floor(Math.random() * row);
                const startCol = Math.floor(Math.random() * col);

                // 尝试在相邻的位置放置块
                let placedInGroup = 0;

                // 使用队列进行广度优先搜索
                const queue: [number, number][] = [[startRow, startCol]];
                const visited = new Set<string>();
                const maxAttempts = 100; // 最大尝试次数
                let attempts = 0;
                if (Math.random() < siameseRandom) {
                    while (queue.length > 0 && placedInGroup < Math.min(maxCount - placed, siamese) && attempts < maxAttempts) {
                        const [r, c] = queue.shift()!;
                        const key = `${r},${c}`;

                        // 检查是否越界或已访问
                        if (r < 0 || r >= row || c < 0 || c >= col || grid[r][c].value !== 0 || visited.has(key)) {
                            attempts++;
                            continue;
                        }
                        // 放置颜色块
                        grid[r][c].value = Number(color)
                        grid[r][c].y = r;
                        grid[r][c].x = c;
                        placedInGroup++;
                        placed++;

                        // 标记为已访问
                        visited.add(key);

                        // 将相邻位置加入队列
                        queue.push([r - 1, c], [r + 1, c], [r, c - 1], [r, c + 1]);
                    }
                }

                // 如果没有放置成功，随机放置剩余的块
                if (placedInGroup === 0) {
                    const emptyPositions: [number, number][] = [];
                    for (let i = 0; i < row; i++) {
                        for (let j = 0; j < col; j++) {
                            if (grid[i][j].value === 0) {
                                emptyPositions.push([i, j]);
                            }
                        }
                    }

                    // 如果没有空白位置，减少数量并重新开始
                    if (emptyPositions.length === 0) {
                        colorCount[color] = Math.max(0, colorCount[color] - 1); // 减少数量
                        break; // 跳出当前颜色的放置循环
                    } else {
                        const randomIndex = Math.floor(Math.random() * emptyPositions.length);
                        const [randomRow, randomCol] = emptyPositions[randomIndex];
                        grid[randomRow][randomCol].value = Number(color);
                        grid[randomRow][randomCol].y = randomRow;
                        grid[randomRow][randomCol].x = randomCol;
                        placedInGroup++;
                        placed++;
                    }
                }
            }
        }
        console.log(".value", grid);
        // this.levelData = grid;
        console.log(Utils.clonObj(this.checkAllColorCount()))
        this.fillSingleColorBlocks(grid, true);
    }
    /**
     *  生成一个关卡二维数组，接收四个参数，row,col,数量，颜色代号1~7数组表示[1,2,3,4,5,6,7],每个色块是2的倍数
     * @param row 行数
     * @param col 列数
     * @param count 数量
     */
    public generateColorGrid2(row: number, col: number, colorBlocks: { value: number, count: number }[]) {
        let grid = Array.from({ length: row }, (_, y) => Array(col).fill(0).map((_, x) => (
            { value: 0, maskCount: 0, maskType: -1, y: y, x: x }
        ))) as levelData[][];
        for (let i = 0; colorBlocks.length > i; i++) {
            let colorData = colorBlocks[i];
            // 收集所有空白位置
            const emptyPositions: [number, number][] = [];
            for (let r = 0; r < row; r++) {
                for (let c = 0; c < col; c++) {
                    if (grid[r][c].value === 0) {
                        emptyPositions.push([r, c]);
                    }
                }
            }
            // 随机打乱空白位置
            emptyPositions.sort(() => Math.random() - 0.5);
            // 填充指定数量的色块
            for (let j = 0; j < colorData.count && j < emptyPositions.length; j++) {
                const [r, c] = emptyPositions[j];
                grid[r][c].value = colorData.value;
                // 以下坐标赋值可删除（初始化时已设置）
            }
        }
        this.fillSingleColorBlocks(grid, true);
    }

    public playNewGuideData(data:number[][]) {
    //    this. 
        let grid = Array.from({ length: 11 }, (_, y) => Array(10).fill(0).map((_, x) => (
            { value: 0, maskCount: 0, maskType: -1, y: y, x: x }
        ))) as levelData[][];
        for (let i = 0; i < data.length; i++) {
            for (let j = 0; j < data[i].length; j++) {
                grid[i][j].value = data[i][j];
            } 
        }
       this.fillSingleColorBlocks(grid, true);
    }

    funca(arr: any[], len: number, out: number[][] = []) {
        console.log("out2", arr, arr.length < len);
        if (arr.length < len) {
            out.push(arr);
            console.log("out3", out);
            return out['flat']();
        }

        let newArr = [arr.splice(0, 1)[0]];
        for (let i = arr.length - 1; i >= 0; i--) {
            let isAdd = true;
            for (let j = 0; j < newArr.length; j++) {
                if (newArr[j] === arr[i]) {
                    isAdd = false;
                    break;
                }
            }
            if (isAdd) {
                newArr.push(arr.splice(i, 1)[0]);
            }
            if (newArr.length >= len) {
                out.push(newArr);
                // 去掉 return 语句，继续处理后续递归
                return this.funca(arr, len, out);
            } else {
                if (i === 0) {
                    out.push(arr.concat(newArr));
                    return out['flat']();
                }
            }
        }
    }






    /**
     * 修改二维数组中的值
     * @param row1 第一个位置的行
     * @param col1 第一个位置的列
     * @param value 第一个位置的值
     **/
    changeLevelData(row: number, col: number, value: number) {
        this.levelData[row][col].value = value;
    }
    /**
     * 检查并削减指定位置色块的遮罩数量
     * @param row 色块所在的行索引
     * @param col 色块所在的列索引
     * @param count 要削减的遮罩数量
     * @returns 返回一个对象，包含削减操作前的遮罩数量和遮罩类型
     */
    checkCutMaskColorCount(row: number, col: number, count: number) {
        // 保存当前位置色块的遮罩数量和遮罩类型到 result 对象中
        const result = { maskCount: this.levelData[row][col].maskCount, maskType: this.levelData[row][col].maskType };
        // 对当前位置色块的遮罩数量进行削减操作
        this.levelData[row][col].maskCount += count;
        // 如果削减后的遮罩数量小于等于 0
        if (this.levelData[row][col].maskCount <= 0) {
            // 将遮罩数量设置为 0
            this.levelData[row][col].maskCount = 0;
            // 将遮罩类型设置为 -1，表示没有遮罩
            this.levelData[row][col].maskType = -1;
        }
        // 返回包含削减操作前的遮罩数量和遮罩类型的对象
        return result
    }

    /**
     * 随机打乱二维数组数据
     * 采用普通算法
     **/
    randomLevelData() {
        let arr = Utils.clonObj(this.levelData)
        for (let i = 0; i < arr.length; i++) {
            for (let j = 0; j < arr[i].length; j++) {
                const randomRow = Math.floor(Math.random() * arr.length);
                const randomCol = Math.floor(Math.random() * arr[i].length);
                // 交换两个位置的值
                const temp = arr[i][j];
                arr[i][j] = arr[randomRow][randomCol];
                arr[randomRow][randomCol] = temp;
            }
        }
        this.levelData = arr;
        return this.levelData;
    }

    /**
     * 随机打乱二维数组数据
     * 采用Fisher-Yates 洗牌算法，节省内存开销
     * @returns 打乱后的二维数组
     */
    randomLevelDatas() {
        const flatIndices: [number, number][] = [];
        for (let row = 0; row < this.levelData.length; row++) {
            for (let col = 0; col < this.levelData[row].length; col++) {
                flatIndices.push([row, col]);
            }
        }
        const flatLength = flatIndices.length;
        for (let i = flatLength - 1; i > 0; i--) {
            const j = Math.floor(Math.random() * (i + 1));
            const [rowI, colI] = flatIndices[i];
            const [rowJ, colJ] = flatIndices[j];

            // 交换元素
            [this.levelData[rowI][colI], this.levelData[rowJ][colJ]] = [this.levelData[rowJ][colJ], this.levelData[rowI][colI]];
            // 更新交换后元素的坐标
            this.levelData[rowI][colI].x = colI;
            this.levelData[rowI][colI].y = rowI;
            this.levelData[rowJ][colJ].x = colJ;
            this.levelData[rowJ][colJ].y = rowJ;
        }
        return this.levelData;
    }


    /**检测二维数据的值是不是全部为0 */
    checkLevelDataAllIsZero() {
        let isZero = true;
        for (let i = 0; i < this.levelData.length; i++) {
            for (let j = 0; j < this.levelData[i].length; j++) {
                if (this.levelData[i][j].value !== 0) {
                    isZero = false;
                }
            }
        }
        return isZero;
    }
    /**
     * 查找this.levelData数据，如果某个色块总数量为1，则自动补齐一个相同的色块
     */
    public fillSingleColorBlocks(arrDatas?: levelData[][], isAll = false) {
        arrDatas = arrDatas || this.levelData;
        const arrData = Utils.copyObj(arrDatas)
        // 统计每种色块的数量
        const colorCount: Record<number, number> = {};
        for (let i = 0; i < arrData.length; i++) {
            for (let j = 0; j < arrData[i].length; j++) {
                const color = arrData[i][j];
                if (color.value > 0) {
                    colorCount[color.value] = (colorCount[color.value] || 0) + 1;
                }
            }
        }
        // 查找数量为1的色块并补齐
        for (const color in colorCount) {
            if (isAll) {
                if (colorCount[color] % 2 !== 0) {
                    // if (colorCount[color] === 1) {
                    // 收集所有空白位置
                    const emptyPositions: [number, number][] = [];
                    for (let i = 0; i < arrData.length; i++) {
                        for (let j = 0; j < arrData[i].length; j++) {
                            if (arrData[i][j].value === 0) {
                                emptyPositions.push([i, j]);
                            }
                        }
                    }
                    // 随机选择一个空白位置
                    if (emptyPositions.length > 0) {
                        const randomIndex = Math.floor(Math.random() * emptyPositions.length);
                        const [row, col] = emptyPositions[randomIndex];
                        arrData[row][col].value = parseInt(color);
                    }
                }
            } else {
                if (colorCount[color] === 1) {
                    const emptyPositions: [number, number][] = [];
                    for (let i = 0; i < arrData.length; i++) {
                        for (let j = 0; j < arrData[i].length; j++) {
                            if (arrData[i][j].value === 0) {
                                emptyPositions.push([i, j]);
                            }
                        }
                    }
                    // 随机选择一个空白位置
                    if (emptyPositions.length > 0) {
                        const randomIndex = Math.floor(Math.random() * emptyPositions.length);
                        const [row, col] = emptyPositions[randomIndex];
                        arrData[row][col].value = parseInt(color);
                    }
                }
            }
        }
        console.log("统计后", arrData)
        this.levelData = arrData;
        return this.levelData;
    }

    /**
     * 检查this.levelData中是否有数量为1的色块
     * @returns 如果有数量为1的色块，则返回true；否则返回false
     */
    public checkLevelDataHasSingleColorBlocks() {
        // 获取每种色块的数量
        const colorCount: Record<number, number> = this.checkAllColorCount().colorCount;
        // 查找数量为1的色块
        for (const color in colorCount) {
            if (colorCount[color] % 2 === 1) {
                return true;
            }
        }

        return false;
    }
    /**
     * 统计每种色块的数量
     * @returns 每种色块的数量对象
     */
    public checkAllColorCount() {
        // 统计每种色块的数量
        const colorCount: Record<number, number> = {};
        const colorCountObj: Record<number, levelData[]> = {};
        let len = 0;
        for (let i = 0; i < this.levelData.length; i++) {
            for (let j = 0; j < this.levelData[i].length; j++) {
                const color = this.levelData[i][j];
                if (color.value > 0) {
                    len++;
                    colorCount[color.value] = (colorCount[color.value] || 0) + 1;
                    if (color.maskType === -1) {
                        if (!colorCountObj[color.value]) {
                            colorCountObj[color.value] = [color];
                        }
                        else {
                            colorCountObj[color.value].push(color);
                        }
                    }
                }
            }
        }
        return { colorCount: colorCount, colorCountObj: colorCountObj, len: len };
    }

    /**
     * 从数组中随机取出 n 个值，不改变原数组长度，节省内存开销
     * @param arr 原始数组
     * @param n 需要取出的值的数量
     * @returns 包含随机取出的值的数组
     */
    getRandomValues<T>(arr: T[], n: number, isNew = false): T[] {
        arr = arr || [];
        if (isNew) {
            arr = Utils.copyObj(arr)
        }
        if (n > arr.length) {
            console.error("n 不能大于数组的长度", n, arr);
            return [];
        }
        const shuffled = arr.slice();
        for (let i = 0; i < n; i++) {
            const randomIndex = Math.floor(Math.random() * (arr.length - i)) + i;
            [shuffled[i], shuffled[randomIndex]] = [shuffled[randomIndex], shuffled[i]];
        }
        return shuffled.slice(0, n);
    }

    
    findShortestPath(grid: number[][], start: [number, number], end: [number, number]): [number, number][] {
        // 方向数组：上，右，下，左
        const directions = [[-1, 0], [0, 1], [1, 0], [0, -1]];
        
        // 创建队列并初始化起点
        const queue: PathNode[] = [{x: start[0], y: start[1]}];
        const visited = new Set<string>([`${start[0]},${start[1]}`]);
    
        // BFS搜索
        while (queue.length > 0) {
            const current = queue.shift()!;
            
            // 到达终点时回溯路径
            if (current.x === end[0] && current.y === end[1]) {
                const path: [number, number][] = [];
                let node: PathNode | undefined = current;
                while (node) {
                    path.unshift([node.x, node.y]);
                    node = node.parent;
                }
                return path;
            }
    
            // 遍历四个方向
            for (const [dx, dy] of directions) {
                const newX = current.x + dx;
                const newY = current.y + dy;
                
                // 检查新坐标是否有效
                if (newX >= 0 && newY >= 0 && 
                    newX < grid.length && 
                    newY < grid[0].length && 
                    !visited.has(`${newX},${newY}`)) {
                    
                    visited.add(`${newX},${newY}`);
                    queue.push({
                        x: newX,
                        y: newY,
                        parent: current
                    });
                }
            }
        }
        
        return []; // 无路径时返回空数组
    }
}
export interface levelData {
    /**色块的值 */
    value: number,
    /**遮罩类型 */
    maskType: number,
    /**遮罩数量 */
    maskCount: number,
    x: number,
    y: number,
}
export interface PathNode {
    x: number;
    y: number;
    parent?: PathNode;
}